package com.example.webrtcproject;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.TextView;

import com.google.gson.Gson;

import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;
import org.webrtc.AudioSource;
import org.webrtc.AudioTrack;
import org.webrtc.Camera1Enumerator;
import org.webrtc.Camera2Enumerator;
import org.webrtc.CameraEnumerator;
import org.webrtc.CameraVideoCapturer;
import org.webrtc.DataChannel;
import org.webrtc.DefaultVideoDecoderFactory;
import org.webrtc.DefaultVideoEncoderFactory;
import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.Logging;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.RendererCommon;
import org.webrtc.SessionDescription;
import org.webrtc.SurfaceTextureHelper;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;

import java.net.URI;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

/**
 * @作者 mazhuang
 *
 * @创建时间 2020/1/21 10:01
 *
 * @文件描述: 此为音视频通话界面包含拨打和接听界面，只需点连接即可实现音视频通话，至于拨打，同意，拒绝三个按钮是为了实现2U中的通话逻辑，测试中大可不必
 * 基本流程是：拨打方与服务端先建立WebSocket连接，服务端会根据拨打方传入的roomId创建一个房间，并将拨打方存在房间内，
 * 进入成功之后，服务端会给拨打方发送“_peer”的消息，
 * 当接收方也进入房间后，接收方也会依照上述流程收到“_peer”的消息 这样代表双方都进入成功
 * 当接听方成功进入房间后，拨打方此时会收到服务器发来的“_new_peer”的消息，代表房间里有另外新的成员加入，
 * 此时的服务器起的作用是控制和转发。
 * 当拨打方收到“_new_peer”，就开始创建SessionDescription，并将创建成功的SessionDescription存入本地（setLocalDescription）,
 * 然后将SessionDescription发送给拨打方，拨打方收到SessionDescription之后，先将其存起来（setRemoteDescription），然后也去
 * 创建自己的SessionDescription，并将其存入本地（setLocalDescription），这样双方都调用了setRemoteDescription和setLocalDescription，从而
 * 持有了对方的SessionDescription，到这一步基本上就连通了，后续会回调onIceCandidate,onAddStream等回调，这样音视频通话就成功了。
 * 后续再发消息时，服务器只是一个转发的角色
 *
 * 参考自 ：
 * CSDN:http://blog.csdn.net/yin13753884368/article
 * Github:https://github.com/taxiao213
 * https://zhuanlan.zhihu.com/p/82446482
 * 微信公众号:他晓
 */

public class WebRtcActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "Call+++++";

    private FrameLayout frameLayout;
    private MySurfaceViewRenderer localSurfaceView;
    private MySurfaceViewRenderer remoteSurfaceView;
    private EglBase eglBase;
    private PeerConnectionFactory peerConnectionFactory;

    private VideoTrack localVideoTrack;
    private PeerConnection peerConnection;
    private List<String> streamList;
    private WebSocketClient webSocketClient;
    private Button btConnect;
    private DataChannel channel;
    private MySdpObserver observer;
    //    private Chronometer timeView;//时间控件
    public CameraVideoCapturer videoCapturer;//视频采集器
    MediaStream localVideoStream;
    MediaStream localAudioSteam;
    String webMessageEventName;
    private MediaConstraints mediaConstraints;
    private String roomName;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.webrtc_layout);
        roomName = getIntent().getStringExtra("roomName");
        mediaConstraints = new MediaConstraints();
        localSurfaceView = new MySurfaceViewRenderer(this);
        remoteSurfaceView = new MySurfaceViewRenderer(this);
        frameLayout = findViewById(R.id.frameContentLayout);
        TextView roomNameView = findViewById(R.id.room_name);
        roomNameView.setText(roomName);
        startAddView(remoteSurfaceView,localSurfaceView);
        btConnect = findViewById(R.id.bt_connect);
        Button btCall = findViewById(R.id.bt_call);
        Button btReFuse = findViewById(R.id.bt_refuse);
        Button btReCall = findViewById(R.id.bt_recall);
        Button changeToAudioBtn = findViewById(R.id.change_to_audio_btn);
        Button changeCameraBtn = findViewById(R.id.change_camera_btn);
        Button changeToVideoBtn = findViewById(R.id.change_to_video_btn);
        Button muteBtn = findViewById(R.id.mute_btn);
        Button speakerBtn = findViewById(R.id.speaker_btn);
        btConnect.setOnClickListener(this);
        btCall.setOnClickListener(this);
        btReCall.setOnClickListener(this);
        btReFuse.setOnClickListener(this);
        changeToAudioBtn.setOnClickListener(this);
        changeCameraBtn.setOnClickListener(this);
        changeToVideoBtn.setOnClickListener(this);
        muteBtn.setOnClickListener(this);
        speakerBtn.setOnClickListener(this);
        localSurfaceView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(localSurfaceView.isFullScreen()){
                    return;
                }
                localSurfaceView.setFullScreen(true);
                remoteSurfaceView.setFullScreen(false);
                startAddView(remoteSurfaceView,localSurfaceView);
            }
        });
        remoteSurfaceView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(remoteSurfaceView.isFullScreen()){
                    return;
                }
                localSurfaceView.setFullScreen(false);
                remoteSurfaceView.setFullScreen(true);
                startAddView(localSurfaceView,remoteSurfaceView);
            }
        });
    }
    //之所以采用动态添加SurfaceViewRenderer控件的方法，
    // 是因为要实现点击对方的画面和自己的画面时能从大到小或者从小到大的切换
    // 其实就是画面大小切换而已
    private void startAddView(MySurfaceViewRenderer smallRender,MySurfaceViewRenderer bigRender) {
        if(frameLayout.getChildAt(0) instanceof MySurfaceViewRenderer){
            frameLayout.removeViewAt(0);
            frameLayout.removeViewAt(0);
        }
        int screenHeight = getScreenHeight(this);
        int screenWidth = getScreenWidth(this);
        FrameLayout.LayoutParams fullParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,FrameLayout.LayoutParams.MATCH_PARENT);
        bigRender.setLayoutParams(fullParams);
        FrameLayout.LayoutParams rightTopParams = new FrameLayout.LayoutParams(screenWidth/4,screenHeight/4);
        rightTopParams.gravity = Gravity.END;
        rightTopParams.setMargins(20,50,20,20);
        smallRender.setLayoutParams(rightTopParams);
        frameLayout.addView(bigRender,0);
        frameLayout.addView(smallRender,1);
    }
    /**
     * 获取屏幕宽度
     */
    public int getScreenWidth(Context context) {
        WindowManager wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.widthPixels;
    }

    /**
     * 获取屏幕高度
     */
    public int getScreenHeight(Context context) {
        WindowManager wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.heightPixels;
    }
    @Override
    public void onClick(View v) {
        if (v != null) {
            switch (v.getId()) {
                case R.id.bt_connect:
                    Log.e(TAG, "onClick: 拨打方点击了连接");
                    connectionWebsocket();
                    break;
                case R.id.bt_call:
                    call();
                    break;
                case R.id.bt_refuse:
                    hangUpPhone();
                    break;
                case R.id.bt_recall:
                    acceptPhone();
                    break;
                case R.id.change_to_audio_btn:
                    changeToAudio();
                    break;
                case R.id.change_camera_btn:
                    changeCamera();
                    break;
                case R.id.change_to_video_btn:
//                    changeToVideo();
                    break;
                case R.id.mute_btn:
                    shutdownAudioStream();
                    break;
                case R.id.speaker_btn:
                    openAudioStream();
                    break;
                default:
                    break;
            }
        }
    }

    /**
     * 切换摄像头
     */
    private void changeCamera() {
        videoCapturer.switchCamera(new CameraVideoCapturer.CameraSwitchHandler() {
            @Override
            public void onCameraSwitchDone(boolean isFront) {
                //这里的boolean代表是否为前置摄像头
                Log.e(TAG, "onCameraSwitchDone: "+isFront);
                if(isFront){
                    localSurfaceView.setMirror(true);
                    sendChangeCameraMessage(true);
                } else {
                    localSurfaceView.setMirror(false);
                    sendChangeCameraMessage(false);
                }
            }

            @Override
            public void onCameraSwitchError(String s) {
                Log.e(TAG, "onCameraSwitchError: "+s);
            }
        });

    }


    @SuppressLint("HandlerLeak")
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg != null) {
                String obj = (String) msg.obj;
                if (!TextUtils.isEmpty(obj)) {
                    switch (obj) {
                        case Constant.OPEN:
                            createPeerConnection();
                            break;
                        case Constant.TIME:
                            showTime();
                            break;
                        default:
                            break;
                    }
                }
            }
        }
    };

    private void showTime() {
//        timeView.setBase(SystemClock.elapsedRealtime());
//        int hour = (int) ((SystemClock.elapsedRealtime() - timeView.getBase()) / 1000 / 60);
//        timeView.setFormat("0" + String.valueOf(hour) + ":%s");
//        timeView.start();
    }

    /**
     * 连接Websocket
     */
    private void connectionWebsocket() {
        try {
            Map<String, String> map = new HashMap<>();
            map.put("origin", "http://meet2.2u.chat:8089");//需要一个请求头，否则websoket连接不成功
            webSocketClient = new WebSocketClient(URI.create(Constant.URL), new Draft_6455(), map) {
                @Override
                public void onOpen(ServerHandshake handshakedata) {
                    setText("已连接");
                    Model model = new Model(Constant.REGISTER, roomName, Constant.CLIENTA);
                    webSocketClient.send(model.toString());
                }


                //自己进房间和对方进房间都是根据Model中的EventName判断，eventname中的值是由服务器所定，自己无法自定义，
                // 后续的都是从Model中的msg中的eventname判断的，这些evenname中的值都可以自己添加或者自定义
                @Override
                public void onMessage(String message) {
                    if (!TextUtils.isEmpty(message)) {
                        Model model = new Gson().fromJson(message, Model.class);
                        if (model != null) {
                            String eventname = model.getEventname();
                            if (!TextUtils.isEmpty(eventname)) {
                                if (Constant.PEER.equals(eventname)) {//自己进入房间陈工
                                    Message msg = new Message();
                                    msg.obj = Constant.OPEN;
                                    handler.sendMessage(msg);
                                } else if (Constant.NEW_PEER.equals(eventname)) {//收到对方进入房间成功的消息
                                    createSessionDescriptionOffer();
                                }
                            } else {
                                WebMessage webMessage = new Gson().fromJson(model.getMsg(), WebMessage.class);
                                if (webMessage == null) {
                                    return;
                                }
                                webMessageEventName = webMessage.getEventname();
                                switch (webMessageEventName) {
                                    case Constant.CALL:
                                        isIncall();
                                        break;
                                    case Constant.AGREE:
//                                        createSessionDescriptionOffer();
                                        break;
                                    case Constant.REFUSE:
                                        break;
                                    case Constant.ICE_CANDIDATE://接收方收到对方发来的SessionDescription，开始做出应答
                                        Message message1 = Message.obtain();
                                        message1.obj = Constant.TIME;
                                        handler.sendMessage(message1);
                                        SessionDescription remoteSessionDescription = webMessage.getSessionDescription();
                                        createSessionDescriptionAnswer(remoteSessionDescription);
                                        break;
                                    case Constant.CANDIDATE://到这一步基本上连通了
                                        //android端直接可以传递IceCandidate对象，但是IOS那边需要用三个参数去创建IceCandidate
                                        //为了迁就ios，只得也去创建
//                                        IceCandidate iceCandidate = webMessage.getIceCandidate();
                                        IceCandidate iceCandidate = new IceCandidate(webMessage.getId(),webMessage.getLabel(),webMessage.getIceCandidate());
                                        peerConnection.addIceCandidate(iceCandidate);
                                        break;
                                    case Constant.CHANGE_CAMERA://收到对方切换摄像头的消息
                                        Log.e(TAG, "onMessage: 收到Constant.CHANGE_CAMERA消息+++++");
                                        remoteSurfaceView.setMirror(webMessage.getFront());
                                        break;
                                    case Constant.CHANGE_TO_AUDIO://收到对方切换到语音的消息
                                        Log.e(TAG, "onMessage: 收到Constant.CHANGE_CAMERA消息+++++");
                                        changeToAudio();
                                        break;
                                    default:
                                        break;
                                }
                            }
                        }
                    }
                }

                @Override
                public void onClose(int code, String reason, boolean remote) {
                    setText("已关闭");//房间进入失败会回调此方法
                    showToast(reason);
                }

                @Override
                public void onError(Exception ex) {
                    setText("出错");
                    showToast(ex.getMessage());
                }
            };
            webSocketClient.connect();
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "socket Exception : " + e.getMessage());
        }
    }
    private void showToast(String content){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                ToastUtil.showToast(WebRtcActivity.this,content);
            }
        });
    }

    /**
     * websoket连接成功之后，开始初始化webrtc相关配置
     */
    private void createPeerConnection() {
        PeerConnectionFactory.InitializationOptions initializationOptions = PeerConnectionFactory.InitializationOptions.builder(this)
                .setEnableInternalTracer(true)
                .setFieldTrials("WebRTC-H264HighProfile/Enabled/")
                .createInitializationOptions();
        PeerConnectionFactory.initialize(initializationOptions);

        //创建EglBase对象
        eglBase = EglBase.create();
        PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
        //是否加密传输，即在SessionDescription的sdp中是否有fingerprint，ios那边需要这个值，否则传递不成功
        options.disableEncryption = false;
        options.disableNetworkMonitor = true;
        DefaultVideoEncoderFactory defaultVideoEncoderFactory = new DefaultVideoEncoderFactory(eglBase.getEglBaseContext(), true, true);
        DefaultVideoDecoderFactory defaultVideoDecoderFactory = new DefaultVideoDecoderFactory(eglBase.getEglBaseContext());
        peerConnectionFactory = PeerConnectionFactory.builder()
                .setVideoDecoderFactory(defaultVideoDecoderFactory)
                .setVideoEncoderFactory(defaultVideoEncoderFactory)
                .setOptions(options)
                .createPeerConnectionFactory();
        // 配置STUN穿透服务器  转发服务器
        List<PeerConnection.IceServer> iceServers = new ArrayList<>();
        PeerConnection.IceServer.Builder iceServerBuilder = PeerConnection.IceServer.builder(Constant.STUN);
        iceServerBuilder.setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK);
        PeerConnection.IceServer iceServer = iceServerBuilder.createIceServer();
        iceServers.add(iceServer);

        streamList = new ArrayList<>();
        PeerConnection.RTCConfiguration configuration = new PeerConnection.RTCConfiguration(iceServers);
        PeerConnectionObserver connectionObserver = getObserver();


        //创建约束
        mediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
        mediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));
        //是否用DTLS传输，android端是否为true都无所谓，ios缺这个不行
        mediaConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));


        peerConnection = peerConnectionFactory.createPeerConnection(configuration,connectionObserver);
        /*
        DataChannel.Init 可配参数说明：
        ordered：是否保证顺序传输；
        maxRetransmitTimeMs：重传允许的最长时间；
        maxRetransmits：重传允许的最大次数；
        */
        DataChannel.Init init = new DataChannel.Init();
        if (peerConnection != null) {
            channel = peerConnection.createDataChannel(Constant.CHANNEL, init);
        }
        DateChannelObserver channelObserver = new DateChannelObserver();
        connectionObserver.setObserver(channelObserver);
        initView();
        initObserver();
    }

    /**
     * 初始化SessionDescription观察者，用于创建SessionDescription
     */
    private void initObserver() {
        observer = new MySdpObserver() {
            @Override
            public void onCreateSuccess(SessionDescription sessionDescription) {
                //创建本地SessionDescription成功，调用setLocalDescription，将其存到本地
                peerConnection.setLocalDescription(this, sessionDescription);
                SessionDescription.Type type = sessionDescription.type;
                Log.e(TAG, "onCreateSuccess " + " SessionDescription创建成功，type为：" + type);
                //接下来使用之前的WebSocket实例将offer发送给服务器
                if (type == SessionDescription.Type.OFFER) {//如果自己是拨打方就用offer
                    //呼叫
                    sendMessageAboutOffer(sessionDescription);
                } else if (type == SessionDescription.Type.ANSWER) {//如果自己是接听方，需做出响应，发送SessionDescription
                    //应答
                    sendMessageAboutAnswer(sessionDescription);
                } else if (type == SessionDescription.Type.PRANSWER) {
                    //再次应答
                }
            }
        };

    }

    @NonNull
    private PeerConnectionObserver getObserver() {
        return new PeerConnectionObserver() {
            @Override
            public void onIceCandidate(IceCandidate iceCandidate) {
                super.onIceCandidate(iceCandidate);
                Log.e(TAG, "onIceCandidate回调成功，并开始调用setIceCandidate()");
                sendMessageAboutIceCandidate(iceCandidate);
            }

            @Override
            public void onAddStream(MediaStream mediaStream) { //收到对方的发来的音视频流，用来显示
                super.onAddStream(mediaStream);
                Log.d(TAG, "onAddStream : " + mediaStream.toString());
                List<VideoTrack> videoTracks = mediaStream.videoTracks;
                if (videoTracks != null && videoTracks.size() > 0) {
                    VideoTrack videoTrack = videoTracks.get(0);
                    if (videoTrack != null) {
                        videoTrack.addSink(remoteSurfaceView);
                    }
                }
                List<AudioTrack> audioTracks = mediaStream.audioTracks;
                if (audioTracks != null && audioTracks.size() > 0) {
                    AudioTrack audioTrack = audioTracks.get(0);
                    if (audioTrack != null) {
                        audioTrack.setVolume(Constant.VOLUME);
                    }
                }
            }
        };
    }
    private void sendMessage(String message) {
        byte[] msg = message.getBytes();
        DataChannel.Buffer buffer = new DataChannel.Buffer(ByteBuffer.wrap(msg), false);
        channel.send(buffer);
    }

    /**
     * 初始化view
     */
    private void initView() {
        initSurfaceView(localSurfaceView,true);
        initSurfaceView(remoteSurfaceView,true);
        createLocalVideoCapture(localSurfaceView);
        createLocalAudioCapture();
    }

    private void changeToAudio() {
        localVideoTrack.removeSink(localSurfaceView);
        peerConnection.removeStream(localVideoStream);
        Model model = new Model(Constant.SEND, roomName, Constant.CLIENTA);
        WebMessage webMessage = new WebMessage();
        webMessage.setEventname(Constant.CHANGE_TO_AUDIO);
        webMessage.setSocketId(Constant.CLIENTA);
        model.setMsg(webMessage.toString());
        String text = model.toString();
        webSocketClient.send(text);
        Log.e(TAG, "sendMessageAboutOffer() " + "发送SessionDescription成功");

    }
    /**
     * 创建本地视频采集器
     *
     * @param localSurfaceView
     */
    private void createLocalVideoCapture(SurfaceViewRenderer localSurfaceView){
        VideoSource videoSource = peerConnectionFactory.createVideoSource(true);
        SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create(Thread.currentThread().getName(), eglBase.getEglBaseContext());
        //开启摄像头
        videoCapturer = createVideoCapturer();
        videoCapturer.initialize(surfaceTextureHelper, this, videoSource.getCapturerObserver());
        videoCapturer.startCapture(Constant.VIDEO_RESOLUTION_WIDTH, Constant.VIDEO_RESOLUTION_HEIGHT, Constant.VIDEO_FPS);

        localVideoTrack = peerConnectionFactory.createVideoTrack(Constant.VIDEO_TRACK_ID, videoSource);
        localVideoTrack.addSink(localSurfaceView);
        localVideoStream = peerConnectionFactory.createLocalMediaStream(Constant.LOCAL_VIDEO_STREAM);
        localVideoStream.addTrack(localVideoTrack);
        peerConnection.addTrack(localVideoTrack, streamList);
        peerConnection.addStream(localVideoStream);
    }
    /**
     * 创建本地音频采集器
     */
    private void createLocalAudioCapture() {
        //语音
        MediaConstraints audioConstraints = new MediaConstraints();
        //回声消除
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googEchoCancellation", "true"));
        //自动增益
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googAutoGainControl", "true"));
        //高音过滤
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googHighpassFilter", "true"));
        //噪音处理
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googNoiseSuppression", "true"));
        AudioSource audioSource = peerConnectionFactory.createAudioSource(audioConstraints);
        AudioTrack localAudioTrack = peerConnectionFactory.createAudioTrack(Constant.AUDIO_TRACK_ID, audioSource);
        localAudioSteam = peerConnectionFactory.createLocalMediaStream(Constant.LOCAL_AUDIO_STREAM);
        localAudioSteam.addTrack(localAudioTrack);
        localAudioTrack.setVolume(Constant.VOLUME);
        peerConnection.addTrack(localAudioTrack, streamList);
        peerConnection.addStream(localAudioSteam);
    }

    /**
     * 用于开启静音
     */
    private void shutdownAudioStream(){
        peerConnection.removeStream(localAudioSteam);
    }

    /**
     * 用于关闭静音
     */
    private void openAudioStream(){
        peerConnection.addStream(localAudioSteam);
    }
    /**
     * 初始化Surfaceview 包括设置是否镜像，屏幕常亮等等
     *
     * @param localSurfaceView
     */
    private void initSurfaceView(SurfaceViewRenderer localSurfaceView, boolean isMirror) {
        localSurfaceView.init(eglBase.getEglBaseContext(), null);
        localSurfaceView.setMirror(isMirror);//录制的视频是否要镜像，这个决定了显示的画面是不是倒影，前置摄像头要镜像，后置的不需要
        localSurfaceView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
        localSurfaceView.setKeepScreenOn(true);
        localSurfaceView.setZOrderMediaOverlay(true);
        localSurfaceView.setEnableHardwareScaler(false);
    }

    /**
     * 拨打方收到对方进入房间，就开始创建SessionDescription，并发送给对方
     */
    private void createSessionDescriptionOffer() {
        Log.e(TAG, "createSessionDescriptionOffer: " + "拨打方开始创建SessionDescription");
        peerConnection.createOffer(observer, mediaConstraints);
    }
    /**
     * 接听方收到拨打方发的SessionDescription之后，先调用setRemoteDescription，将对方的SessionDescription存起来
     * 然后创建自己的SessionDescription并发送给拨打方
     * 这样双方都调用了setRemoteDescription和setLocalDescription
     * 双方都持有了对方的和自己的SessionDescription
     *
     * */
    private void createSessionDescriptionAnswer(SessionDescription remoteSessionDescription) {
        Log.e(TAG, "createSessionDescriptionAnswer: " + "收到SessionDescription后做出响应继续创建SessionDescription");
        peerConnection.setRemoteDescription(observer, remoteSessionDescription);
        peerConnection.createAnswer(observer, mediaConstraints);
    }
    /**
     * 拨打方创建完SessionDescription后开始使用WebSocket发送SessionDescription给接听方
     *
     * @param sdpDescription
     */
    private void sendMessageAboutOffer(SessionDescription sdpDescription) {
        Log.e(TAG, "sendMessageAboutOffer: SessionDescription：" + "拨打方开始发送SessionDescription");
        Model model = new Model(Constant.SEND, roomName, Constant.CLIENTA);
        WebMessage webMessage = new WebMessage();
        webMessage.setEventname(Constant.ICE_CANDIDATE);
        webMessage.setSocketId(Constant.CLIENTA);
        webMessage.setSessionDescription(sdpDescription);
        model.setMsg(webMessage.toString());
        String text = model.toString();
        webSocketClient.send(text);
        Log.e(TAG, "sendMessageAboutOffer() " + "发送SessionDescription成功");
    }

    /**
     * 接收方创建完SessionDescription后使用WebSocket发送SessionDescription给拨打方
     *
     * @param sdpDescription
     */
    private void sendMessageAboutAnswer(SessionDescription sdpDescription) {
        Log.e(TAG, "sendMessageAboutAnswer: SessionDescription：" + "接收方收到对方发来的SessionDescription开始做出响应");
        Model model = new Model(Constant.SEND, roomName, Constant.CLIENTA);
        WebMessage webMessage = new WebMessage();
        webMessage.setSocketId(Constant.CLIENTA);
        webMessage.setEventname(Constant.ICE_CANDIDATE);
        webMessage.setSessionDescription(sdpDescription);
        model.setMsg(webMessage.toString());
        String text = new Gson().toJson(model);
        webSocketClient.send(text);
    }

    /**
     * 因为前置摄像头和后置摄像头是有镜像的，每次切换完摄像头，都要设置一下镜像，
     * 当某一方切换摄像头后，需要告知对方，然后让对方去选择是否设置镜像
     *
     * @param isFront
     */
    private void sendChangeCameraMessage(boolean isFront){
        Model model = new Model(Constant.SEND, roomName, Constant.CLIENTA);
        WebMessage webMessage = new WebMessage();
        webMessage.setEventname(Constant.CHANGE_CAMERA);
        webMessage.setSocketId(Constant.CLIENTA);
        webMessage.setFront(isFront);
        model.setMsg(webMessage.toString());
        String text = model.toString();
        webSocketClient.send(text);
        Log.e(TAG, "sendMessageAboutOffer() " + "发送SessionDescription成功");
    }

    /**
     * 呼叫
     *
     * @param iceCandidate
     */
    private void sendMessageAboutIceCandidate(IceCandidate iceCandidate) {
        Log.e(TAG, "setIceCandidate: 发送了Constant.CANDIDATE消息");
        Model model = new Model(Constant.SEND, roomName, Constant.CLIENTA);
        WebMessage webMessage = new WebMessage();
        webMessage.setSocketId(Constant.CLIENTA);
        webMessage.setEventname(Constant.CANDIDATE);
        webMessage.setIceCandidate(iceCandidate.sdp);
//        webMessage.setIceCandidate(iceCandidate);
        webMessage.setId(iceCandidate.sdpMid);
        webMessage.setLabel(iceCandidate.sdpMLineIndex);
        model.setMsg(webMessage.toString());
        webSocketClient.send(model.toString());
    }

    /**
     * 呼叫
     */
    private void call() {
        Model model = new Model(Constant.SEND, roomName, Constant.CLIENTA);
        WebMessage webMessage = new WebMessage();
        webMessage.setSocketId(Constant.CLIENTA);
        webMessage.setEventname(Constant.CALL);
        webMessage.setId(Constant.CLIENTA);
        model.setMsg(webMessage.toString());
        String content = model.toString();
        webSocketClient.send(content);
    }

    /**
     * 是否接听
     */
    private void isIncall() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                ToastUtil.showToast(WebRtcActivity.this, "收到来电，是否接听");
            }
        });
    }

    /**
     * 接听
     */
    private void acceptPhone() {
        Log.e(TAG, "acceptPhone: 接听了电话");
        Model model = new Model(Constant.SEND, roomName, Constant.CLIENTA);
        WebMessage webMessage = new WebMessage();
        webMessage.setSocketId(Constant.CLIENTA);
        webMessage.setEventname(Constant.AGREE);
        model.setMsg(webMessage.toString());
        webSocketClient.send(model.toString());
    }

    /**
     * 拒绝
     */
    private void hangUpPhone() {
        Log.e(TAG, "hangUpPhone: 拒绝了电话");
        Model model = new Model(Constant.SEND, roomName, Constant.CLIENTA);
        WebMessage webMessage = new WebMessage();
        webMessage.setSocketId(Constant.CLIENTA);
        webMessage.setEventname(Constant.REFUSE);
        model.setMsg(webMessage.toString());
        webSocketClient.send(model.toString());
    }


    private void setText(final String st) {
        runOnUiThread(() -> btConnect.setText(st));
    }

    /**
     * 准备摄像头
     *
     * @return
     */
    private CameraVideoCapturer createVideoCapturer() {
        if (Camera2Enumerator.isSupported(this)) {
            return createCameraCapturer(new Camera2Enumerator(this));
        } else {
            return createCameraCapturer(new Camera1Enumerator(true));
        }
    }

    /**
     * 默认获取的是前置摄像头
     * @param enumerator
     * @return
     */
    private CameraVideoCapturer createCameraCapturer(CameraEnumerator enumerator) {
        final String[] deviceNames = enumerator.getDeviceNames();
        for (String deviceName : deviceNames) {
            if (enumerator.isFrontFacing(deviceName)) {
                CameraVideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);
                if (videoCapturer != null) {
                    return videoCapturer;
                }
            }
        }
        for (String deviceName : deviceNames) {
            if (!enumerator.isFrontFacing(deviceName)) {
                Logging.d(TAG, "Creating other camera captor.");
                CameraVideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);
                if (videoCapturer != null) {
                    return videoCapturer;
                }
            }
        }
        return null;
    }

    private void close() {
        if (peerConnection != null) {
            peerConnection.close();
        }
        if (webSocketClient != null) {
            webSocketClient.close();
        }
        if (localSurfaceView != null) {
            localSurfaceView.release();
        }
        if (remoteSurfaceView != null) {
            remoteSurfaceView.release();
        }
        if(videoCapturer!=null){
            try {
                videoCapturer.stopCapture();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        close();
    }

}
